package com.qianli.cashmama.trade.openApi.job;

import com.aliyun.openservices.shade.org.apache.commons.codec.binary.Base64;
import com.dangdang.ddframe.job.api.ShardingContext;
import com.dangdang.ddframe.job.api.simple.SimpleJob;
import com.fqgj.base.services.redis.RedisClient;
import com.fqgj.common.api.Page;
import com.fqgj.common.api.Response;
import com.fqgj.common.utils.CollectionUtils;
import com.fqgj.common.utils.StringUtils;
import com.fqgj.log.util.Constants;
import com.fqgj.xjd.user.client.UserContactService;
import com.fqgj.xjd.user.client.UserDeviceService;
import com.fqgj.xjd.user.client.request.ShumeiDevice;
import com.fqgj.xjd.user.client.response.UserContactAddressBook;
import com.fqgj.xjd.user.client.response.UserContactSms;
import com.qianli.cashmama.product.facade.result.ProductCategory;
import com.qianli.cashmama.trade.common.enums.TradeStatusEnum;
import com.qianli.cashmama.trade.common.utils.TradeConfigUtil;
import com.qianli.cashmama.trade.dao.TOpenApiPushStatusDao;
import com.qianli.cashmama.trade.dao.TTradeDao;
import com.qianli.cashmama.trade.entity.TOpenApiPushStatusEntity;
import com.qianli.cashmama.trade.entity.TTradeEntity;
import com.qianli.cashmama.trade.entity.vos.PushStatsVo;
import com.qianli.cashmama.trade.integration.product.ProductIntegrationService;
import com.qianli.cashmama.trade.openApi.TradeSynchronizationService;
import com.qianli.cashmama.trade.openApi.enums.MerchantEnum;
import com.qianli.cashmama.trade.openApi.enums.PushStepEnum;
import com.qianli.cashmama.trade.openApi.utils.DingTalkPushUtils;
import com.qianli.cashmama.trade.openApi.utils.contact.DeviceContact;
import com.qianli.cashmama.trade.openApi.utils.contact.DeviceData;
import com.qianli.cashmama.trade.openApi.vendor.inner.request.InnerPushRequest;
import com.robert.vesta.util.IdUtils;
import com.robert.vesta.util.IpUtils;
import org.apache.logging.log4j.ThreadContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Created with IntelliJ IDEA.
 * User: sm
 * Date: 2020-12-02
 * Time: 13:58
 */
@Service
public class PushRetryJob {
    private static final Logger logger = LoggerFactory.getLogger(PushRetryJob.class);

    private static ExecutorService firstPool = Executors.newFixedThreadPool(30);
    private static ExecutorService secondPool = Executors.newFixedThreadPool(30);
    private static ExecutorService thirdPool = Executors.newFixedThreadPool(10);

    public static String url = "https://oapi.dingtalk.com/robot/send?access_token=f313119633e094d4a308e6eca6e1845e90e8ab77672b8cb1fab703cbc32b7307";

    @Autowired
    private RedisClient redisClient;

    @Autowired
    private TradeConfigUtil configUtil;

    @Autowired
    private TTradeDao tTradeDao;

    @Autowired
    private TradeSynchronizationService tradeSynchronizationService;

    @Autowired
    private TOpenApiPushStatusDao openApiPushStatusDao;
    @Autowired
    private ProductIntegrationService productIntegrationService;

    @Autowired
    private UserDeviceService userDeviceService;

    @Autowired
    private UserContactService userContactService;


    private boolean checkImportantInfo(String userCode) {
        Response<ShumeiDevice> shumeiDeviceByUserCode = userDeviceService.getShumeiDeviceByUserCode(userCode);
        if (shumeiDeviceByUserCode == null || shumeiDeviceByUserCode.getData() == null) {
            logger.info("== 数美信息不存在 ==,userCode:{}", userCode);
            return false;
        }

        UserContactAddressBook userContactAddressBook = userContactService.getUserDeviceContactByUserCode(userCode).getData();
        String contactUrl = null;
        if (Objects.nonNull(userContactAddressBook)) {
            contactUrl = userContactAddressBook.getContactUrl();
        }
        if (StringUtils.isEmpty(contactUrl)) {
            logger.info("== contact 信息不存在 ==,userCode:{}", userCode);
            return false;
        }

        return true;

    }

    @Scheduled(fixedDelay = 1000L * 30)
    public void firstPushRetry() {

        String hostIp = IpUtils.getHostIp();
        logger.info("==开启一推重试任务==,ip:{}", hostIp);

        if (!hostIp.equals(configUtil.pushJobRunIp())) {
            logger.info("==开启一推重试任务==, 当前机器ip不是job执行机器,当前iP:{},目标IP:{}", hostIp, configUtil.pushJobRunIp());
            return;
        }

        if (!configUtil.getAllowPushSteps().contains("1")) {
            logger.info("==开启一推重试任务==,开关未开启");
            return;
        }


        logger.info("==开启一推重试任务==");
        Page page = new Page();
        page.setCurrentPage(1);
        page.setPageSize(100);
        page.setPageSize(configUtil.pushSelectMaxSize());
        List<TTradeEntity> firstPushWaittingList = tTradeDao.getFirstPushWaittingList(page);

        if (CollectionUtils.isEmpty(firstPushWaittingList)) {
            logger.info("==开启一推重试任务==,size:0");
            return;
        }

        //获取一推待处理的订单
        firstPushWaittingList.forEach(tTradeEntity -> {
            String allowPushOrders = configUtil.getAllowPushOrders();
            String allowPushCategoryCode = configUtil.getAllowPushCategoryCode();

            logger.info("==开启1推重试任务==,allowPushOrders:{},allowPushCategoryCode:{}", allowPushOrders, allowPushCategoryCode);
            if (!StringUtils.isEmpty(allowPushOrders)) {
                logger.info("==开启1推重试任务==,allowPushOrders不为空");
                if (!allowPushOrders.contains(tTradeEntity.getTradeNo())) {
                    return;
                }
            }

            if (!StringUtils.isEmpty(allowPushCategoryCode)) {
                logger.info("==开启1推重试任务==,allowPushCategoryCode不为空");
                if (!allowPushCategoryCode.contains(tTradeEntity.getProductCategory())) {
                    return;
                }
            }

            logger.info("==开启一推重试任务==,tradeNo:{}", tTradeEntity.getTradeNo());
            ProductCategory productCategory = productIntegrationService.getCategoryByMerchantCode(tTradeEntity.getMerchantCode());
            TOpenApiPushStatusEntity tOpenApiPushStatusEntity = openApiPushStatusDao.selectOneByTradeNo(tTradeEntity.getTradeNo());
            if (tOpenApiPushStatusEntity != null) {
                int maxRetryTimes = tOpenApiPushStatusEntity.getRetryTimes() + 1;
                if (maxRetryTimes > configUtil.pushMaxRetryTimes()) {
                    tOpenApiPushStatusEntity.setRunningStatus(2);
                    openApiPushStatusDao.updateByPrimaryKey(tOpenApiPushStatusEntity);
                    logger.info("== 超过最大重试次数 ==");
                    return;
                }
            }

            String key = "first_push_trade_no11::" + tTradeEntity.getTradeNo();

            try {
                logger.info("== 重试中 ==,tradeNo:{},key:{},value:{}", tTradeEntity.getTradeNo(), key, redisClient.getNumber(key));
                if (redisClient.get(key) != null && redisClient.getNumber(key) == 1) {
                    logger.info("== 重试中 ==,tradeNo:{}", tTradeEntity.getTradeNo());
                    return;
                }
            } catch (Exception e) {
                logger.error("== 重试中 ==,tradeNo:{}", tTradeEntity.getTradeNo(), e);
            }

            firstPool.execute(() -> {
                String spanId = Long.toString(IdUtils.genId());
                String traceId = Long.toString(IdUtils.genId());
                String parentSpanId = "0";

                ThreadContext.put(Constants.TRACE_ID, traceId);
                ThreadContext.put(Constants.SPAN_ID, spanId);
                ThreadContext.put(Constants.PARENT_SPAN_ID, parentSpanId);

                redisClient.set(key, 1, 120);
                InnerPushRequest innerPushRequest = new InnerPushRequest()
                        .setTradeNo(tTradeEntity.getTradeNo())
                        .setUserCode(tTradeEntity.getUserCode())
                        .setMerchantCode(tTradeEntity.getMerchantCode())
                        .setStepCode(PushStepEnum.INNER_STEP_ONE.getStepCode())
                        .setDomianUrl(productCategory.getMerchantDoaminUrl())
                        .setToken(productCategory.getMerchantPublicKey());

                tradeSynchronizationService.dataSync(MerchantEnum.INNER_SYSTEM, innerPushRequest);
                redisClient.del(key);
            });

        });
    }


    @Scheduled(fixedDelay = 1000L * 30)
    public void secondPushRetry() {
        String hostIp = IpUtils.getHostIp();
        logger.info("==开启2推重试任务==,ip:{},steps:{}", hostIp, configUtil.getAllowPushSteps());

        if (!hostIp.equals(configUtil.pushJobRunIp())) {
            logger.info("==开启2推重试任务==, 当前机器ip不是job执行机器,当前iP:{},目标IP:{}", hostIp, configUtil.pushJobRunIp());
            return;
        }

        if (!configUtil.getAllowPushSteps().contains("2")) {
            logger.info("==开启2推重试任务==,开关未开启");
            return;
        }


        Page page = new Page();
        page.setCurrentPage(1);
        page.setPageSize(configUtil.pushSelectMaxSize());
        List<TTradeEntity> secondPushWaittingList = tTradeDao.getSecondPushWaittingList(page);

        if (CollectionUtils.isEmpty(secondPushWaittingList)) {
            logger.info("==开启2推重试任务==,size:0");
            return;
        }

        //获取一推待处理的订单
        secondPushWaittingList.forEach(tTradeEntity -> {
            TOpenApiPushStatusEntity tOpenApiPushStatusEntity = openApiPushStatusDao.selectOneByTradeNo(tTradeEntity.getTradeNo());
            int maxRetryTimes = tOpenApiPushStatusEntity.getRetryTimes() + 1;
            if (maxRetryTimes > 2 * configUtil.pushMaxRetryTimes()) {
                tOpenApiPushStatusEntity.setRunningStatus(2);
                openApiPushStatusDao.updateByPrimaryKey(tOpenApiPushStatusEntity);
                logger.info("== 超过最大重试次数 ==");
                return;
            }

            if (!checkImportantInfo(tTradeEntity.getUserCode())) {
                tOpenApiPushStatusEntity.setRunningStatus(2);
                openApiPushStatusDao.updateByPrimaryKey(tOpenApiPushStatusEntity);
                logger.error("== 二推检测重要信息发生异常 ==");
                return;
            }

            String allowPushOrders = configUtil.getAllowPushOrders();
            String allowPushCategoryCode = configUtil.getAllowPushCategoryCode();

            logger.info("==开启2推重试任务==,allowPushOrders:{},allowPushCategoryCode:{}", allowPushOrders, allowPushCategoryCode);
            if (!StringUtils.isEmpty(allowPushOrders)) {
                logger.info("==开启2推重试任务==,allowPushOrders不为空");
                if (!allowPushOrders.contains(tTradeEntity.getTradeNo())) {
                    return;
                }
            }

            if (!StringUtils.isEmpty(allowPushCategoryCode)) {
                logger.info("==开启2推重试任务==,allowPushCategoryCode不为空");
                if (!allowPushCategoryCode.contains(tTradeEntity.getProductCategory())) {
                    return;
                }
            }




            String key = "second_push_trade_no::" + tTradeEntity.getTradeNo();
            try {
                if (redisClient.get(key) != null && redisClient.getNumber(key) == 1) {
                    logger.info("== 重试中 ==,tradeNo:{}", tTradeEntity.getTradeNo());
                    return;
                }
            } catch (Exception e) {
                logger.error("== 重试中2 ==,tradeNo:{},value:{}", tTradeEntity.getTradeNo(), redisClient.getNumber(key), e);
            }

            secondPool.execute(() -> {
                String spanId = Long.toString(IdUtils.genId());
                String traceId = Long.toString(IdUtils.genId());
                String parentSpanId = "0";

                ThreadContext.put(Constants.TRACE_ID, traceId);
                ThreadContext.put(Constants.SPAN_ID, spanId);
                ThreadContext.put(Constants.PARENT_SPAN_ID, parentSpanId);

                redisClient.set(key, 1, 120);
                InnerPushRequest innerPushRequest = new InnerPushRequest()
                        .setTradeNo(tTradeEntity.getTradeNo())
                        .setUserCode(tTradeEntity.getUserCode())
                        .setMerchantCode(tTradeEntity.getMerchantCode())
                        .setStepCode(PushStepEnum.INNER_STEP_TWO.getStepCode());

                try {
                    tradeSynchronizationService.dataSync(MerchantEnum.INNER_SYSTEM, innerPushRequest);
                    redisClient.del(key);
                } catch (Exception e) {

                }
            });

        });
    }


    @Scheduled(fixedDelay = 1000L * 30)
    public void orderCreateRetry() {
        String hostIp = IpUtils.getHostIp();
        logger.info("==开启3推重试任务==,ip:{}", hostIp);


        if (!hostIp.equals(configUtil.pushJobRunIp())) {
            logger.info("==开启3推重试任务==, 当前机器ip不是job执行机器,当前iP:{},目标IP:{}", hostIp, configUtil.pushJobRunIp());
            return;
        }

        if (!configUtil.getAllowPushSteps().contains("3")) {
            logger.info("==开启3推重试任务==,开关未开启");
            return;
        }


        Page page = new Page();
        page.setCurrentPage(1);
        page.setPageSize(configUtil.pushSelectMaxSize());
        List<TTradeEntity> thirdPushWaittingList = tTradeDao.getThirdPushWaittingList(page);

        if (CollectionUtils.isEmpty(thirdPushWaittingList)) {
            logger.info("==开启3推重试任务==,size:0");
            return;
        }

        //获取一推待处理的订单
        thirdPushWaittingList.forEach(tTradeEntity -> {
            String allowPushOrders = configUtil.getAllowPushOrders();
            String allowPushCategoryCode = configUtil.getAllowPushCategoryCode();

            logger.info("==开启3推重试任务==,allowPushOrders:{},allowPushCategoryCode:{}", allowPushOrders, allowPushCategoryCode);
            if (!StringUtils.isEmpty(allowPushOrders)) {
                logger.info("==开启3推重试任务==,allowPushOrders不为空");
                if (!allowPushOrders.contains(tTradeEntity.getTradeNo())) {
                    return;
                }
            }

            if (!StringUtils.isEmpty(allowPushCategoryCode)) {
                logger.info("==开启3推重试任务==,allowPushCategoryCode不为空");
                if (!allowPushCategoryCode.contains(tTradeEntity.getProductCategory())) {
                    return;
                }
            }
            if (tTradeEntity.getOrderStatus() != TradeStatusEnum.CREATE_SUCCESS.getStatus()) {
                logger.error("== 当前订单状态不是初始态-- 1 ==");
                return;
            }
            TOpenApiPushStatusEntity tOpenApiPushStatusEntity = openApiPushStatusDao.selectOneByTradeNo(tTradeEntity.getTradeNo());
            int maxRetryTimes = tOpenApiPushStatusEntity.getRetryTimes() + 1;
            if (maxRetryTimes > 3 * configUtil.pushMaxRetryTimes()) {
                tOpenApiPushStatusEntity.setRunningStatus(2);
                openApiPushStatusDao.updateByPrimaryKey(tOpenApiPushStatusEntity);
                logger.info("== 超过最大重试次数 ==");
                return;
            }

            String key = "third_push_trade_no::" + tTradeEntity.getTradeNo();
            try {
                if (redisClient.get(key) != null && redisClient.getNumber(key) == 1) {
                    logger.info("== 重试中 ==,tradeNo:{}", tTradeEntity.getTradeNo());
                    return;
                }
            } catch (Exception e) {
                logger.error("== 重试中 ==,tradeNo:{}", tTradeEntity.getTradeNo(), e);
            }

            thirdPool.execute(() -> {
                String spanId = Long.toString(IdUtils.genId());
                String traceId = Long.toString(IdUtils.genId());
                String parentSpanId = "0";

                ThreadContext.put(Constants.TRACE_ID, traceId);
                ThreadContext.put(Constants.SPAN_ID, spanId);
                ThreadContext.put(Constants.PARENT_SPAN_ID, parentSpanId);

                redisClient.set(key, 1, 120);
                InnerPushRequest innerPushRequest = new InnerPushRequest()
                        .setTradeNo(tTradeEntity.getTradeNo())
                        .setUserCode(tTradeEntity.getUserCode())
                        .setMerchantCode(tTradeEntity.getMerchantCode())
                        .setStepCode(PushStepEnum.CREATE_ORDER.getStepCode());

                boolean createOrderSuccess = tradeSynchronizationService.dataSync(MerchantEnum.INNER_SYSTEM, innerPushRequest);
                logger.info("== createOrderSuccess :{},tradeNo:{} ==", createOrderSuccess, tTradeEntity.getTradeNo());
                redisClient.del(key);
                if (createOrderSuccess) {
                    if (TradeStatusEnum.CREATE_SUCCESS.getStatus() == tTradeEntity.getOrderStatus()) {
                        tTradeEntity.setOrderStatus(TradeStatusEnum.AUDIT_WATTING.getStatus());
                        tTradeDao.updateByPrimaryKey(tTradeEntity);
                    } else {
                        logger.error("== 当前订单状态不是初始态 1 ==");
                    }

                }
            });

        });
    }


    @Scheduled(fixedDelay = 1000 * 60 * 5)
    public void dd() {

        List<PushStatsVo> pushStatsVos = openApiPushStatusDao.pushStatusStats();

        Map<Integer, Integer> firstMap = new HashMap<>();
        Map<Integer, Integer> secondMap = new HashMap<>();
        Map<Integer, Integer> maxRetryMap = new HashMap<>();

        pushStatsVos.forEach(s -> {
            if (s.getFirst_push_status() != 1) {
                firstMap.put(s.getFirst_push_status(), s.getCnt());
                if (s.getRunning_status() != 1) {
                    maxRetryMap.put(1, s.getCnt());
                }
            }

            if (s.getFirst_push_status() == 1 && s.getSecond_push_status() != 1) {
                secondMap.put(s.getSecond_push_status(), s.getCnt());
                if (s.getRunning_status() != 1) {
                    maxRetryMap.put(2, s.getCnt());
                }
            }

        });

        String content = compostContent(firstMap, "dc-first:");
        content += "\r" + compostContent(secondMap, "dc-second:");
        content += "\r" + compostContent(maxRetryMap, "dc-reTry:");

//        sentDD("dc-stats", content);
    }


    private String compostContent(Map<Integer, Integer> statusMap, String key) {
        String content = "\r" + key + "";
        if (CollectionUtils.isEmpty(statusMap)) {
            content += "\r 暂无数据处理";
            return content;
        }
        for (Integer st : statusMap.keySet()) {
            content += "\r 状态：" + st + " 数量 " + statusMap.get(st) + "";
        }


        return content;


    }


    private void sentDD(String key, String content) {
        try {
            logger.info("== 推送钉钉数据提醒 ==");
            Long timestamp = System.currentTimeMillis();
            String secret = "this is secret";

            String stringToSign = timestamp + "\n" + secret;
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256"));
            byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8"));
            String sign = URLEncoder.encode(new String(Base64.encodeBase64(signData)), "UTF-8");

            DingTalkPushUtils.pushToAgent(configUtil.ddAgentUrl(), url + "&timestamp=" + timestamp + "&sign=" + sign, key + (StringUtils.isEmpty(content) ? "：暂无数据处理" : ("：" + content)) + "\r");
        } catch (NoSuchAlgorithmException e) {
            logger.error("== 推送钉钉数据提醒 异常1==", e);
        } catch (InvalidKeyException e) {
            logger.error("== 推送钉钉数据提醒 异常2==", e);
        } catch (UnsupportedEncodingException e) {
            logger.error("== 推送钉钉数据提醒 异常3==", e);
        }
    }


}
